package com.yaorange.web.controller.certificate;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson2.JSON;
import com.github.pagehelper.PageHelper;
import com.yaorange.certificate.domain.NjtUserPerfect;
import com.yaorange.certificate.vo.NjtCertificateVo;
import com.yaorange.common.config.RuoYiConfig;
import com.yaorange.common.exception.ServiceException;
import com.yaorange.common.utils.PageUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.yaorange.common.annotation.Log;
import com.yaorange.common.core.controller.BaseController;
import com.yaorange.common.core.domain.AjaxResult;
import com.yaorange.common.enums.BusinessType;
import com.yaorange.certificate.domain.NjtCertificate;
import com.yaorange.certificate.service.INjtCertificateService;
import com.yaorange.common.utils.poi.ExcelUtil;
import com.yaorange.common.core.page.TableDataInfo;

/**
 * 合格证打印数据Controller
 *
 * @author coach tam
 * @date 2024-07-17
 */
@RestController
@RequestMapping("/certificate/certificate")
public class NjtCertificateController extends BaseController {
    @Autowired
    private INjtCertificateService njtCertificateService;

    /**
     * 查询合格证打印数据列表
     */
    @PreAuthorize("@ss.hasPermi('certificate:certificate:list')")
    @GetMapping("/list")
    public TableDataInfo list(NjtCertificateVo njtCertificate) {
        // 转换userPerfectString为userPerfect对象
        if (StringUtils.isNotEmpty(njtCertificate.getUserPerfectString())) {
            njtCertificate.setUserPerfect(JSON.parseObject(njtCertificate.getUserPerfectString(), NjtUserPerfect.class));
        }
        PageUtils.startPage();
        List<NjtCertificateVo> list = njtCertificateService.selectNjtCertificateList(njtCertificate);
        return getDataTable(list);
    }

    /**
     * 导出合格证打印数据列表
     */
    @PreAuthorize("@ss.hasPermi('certificate:certificate:export')")
    @Log(title = "合格证打印数据", businessType = BusinessType.EXPORT)
    @PostMapping("/exportAll")
    public void export(HttpServletResponse response, NjtCertificateVo njtCertificate) throws FileNotFoundException {
        //1.加载数据&写入到excel中
        int size = 0;
        int pageSize = 1000;
        int pageNo = 1;
        //使用APACHE POI创建工作簿
        XSSFWorkbook wb;
        XSSFSheet sheet;
        String dicPath = RuoYiConfig.getProfile() + "/excel/";
        String pathname = dicPath + UUID.randomUUID() + ".xlsx";

        try {
            File dic = new File(dicPath);
            if (!dic.exists()) {
                dic.mkdirs();
            }

            ClassPathResource classPathResource = new ClassPathResource("excel/certificate_print_template.xlsx");
            wb = new XSSFWorkbook(classPathResource.getInputStream());
            sheet = wb.getSheetAt(0);
        } catch (Exception e) {
            logger.error("创建工作簿异常", e);
            throw new ServiceException("创建工作簿异常");
        }
        try {
            do {
                //1.1.分批次查询mysql合格证数据
                PageHelper.startPage(pageNo++, pageSize);
                List<NjtCertificateVo> list = njtCertificateService.selectNjtCertificateList(njtCertificate);
                if (CollectionUtils.isEmpty(list)) {
                    //意味着没有新的数据，可以直接下载文件了
                    break;
                }
                size = list.size();
            /*//判断是否有临时文件
            if (new File(pathname).exists()) {
                try {
                    wb = new XSSFWorkbook(new FileInputStream(pathname));
                } catch (Exception e) {
                    logger.error("打开临时文件异常", e);
                }
            }*/
                //1.2.将查询到的mysql数据写入到临时excel文件中
                for (NjtCertificateVo vo : list) {
                    //获取到当前sheet最后一行
                    int lastRowNum = sheet.getLastRowNum();
                    //创建新行
                    XSSFRow row = sheet.createRow(lastRowNum + 1);
                    //创建单元格并写入数据
                    int cellNum = 0;
                    XSSFCell cell = row.createCell(cellNum++);
                    cell.setCellValue(vo.getUserPerfect().getId());
                    cell = row.createCell(cellNum++);
                    cell.setCellValue(vo.getProductName());
                    cell = row.createCell(cellNum++);
                    cell.setCellValue(vo.getProductWeight().toString());
                    cell = row.createCell(cellNum);
                    cell.setCellValue(vo.getUnit());
                }
                //保存到临时文件
                try(FileOutputStream outputStream = new FileOutputStream(pathname)) {
                    wb.write(outputStream);
                } catch (IOException e) {
                    logger.error("写入临时文件异常", e);
                    throw new ServiceException("写入临时文件异常");
                }
            } while (size == pageSize);
        } finally {
            try {
                wb.close();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        //2.将完整的excel文件发送给客户端
        //设置响应头(excel文件)
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        //设置字符集
        response.setCharacterEncoding("UTF-8");
        //读取临时文件,并写入到response的响应流中
        FileInputStream fileInputStream = new FileInputStream(pathname);
        byte[] buffer = new byte[1024];
        try {
            while (fileInputStream.read(buffer) != -1) {
                response.getOutputStream().write(buffer);
            }
        } catch (Exception e) {
            logger.error("读取临时文件异常", e);
            throw new ServiceException("读取临时文件异常");
        } finally {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                throw new ServiceException("关闭临时文件异常");
            }
            //删除临时文件
            new File(pathname).delete();
        }
    }

    //开启一个单线程池（同时只能有一个线程导出临时文件）
    private static final  ExecutorService executorService = Executors.newSingleThreadExecutor();;

    //10000/100000
    private volatile int progress = 0;

    //创建一个信号量
    private final Semaphore semaphore = new Semaphore(1);
    private final ReentrantLock lock = new ReentrantLock();

    @PreAuthorize("@ss.hasPermi('certificate:certificate:export')")
    @Log(title = "创建临时文件", businessType = BusinessType.EXPORT)
    @PostMapping("/tempfile")
    public AjaxResult tempfile() {
        String filename = UUID.randomUUID() + ".xlsx";
        //尝试获取一个信号量
       if (!semaphore.tryAcquire()) {
            throw new ServiceException("导出任务正在进行中，请稍后再试");
        }
        /*if (!lock.tryLock()) {
            throw new ServiceException("导出任务正在进行中，请稍后再试");
        }*/
        //异步导出临时文件,提升响应速度
        executorService.execute(()->{
            logger.info("开始创建临时文件-------");
            //1.加载数据&写入到excel中
            int size = 0;
            int pageSize = 1000;
            int pageNo = 1;
            //使用APACHE POI创建工作簿
            XSSFWorkbook wb;
            XSSFSheet sheet;
            String dicPath = RuoYiConfig.getProfile() + "/excel/";
            String pathname = dicPath + filename;

            try {
                File dic = new File(dicPath);
                if (!dic.exists()) {
                    dic.mkdirs();
                }

                ClassPathResource classPathResource = new ClassPathResource("excel/certificate_print_template.xlsx");
                wb = new XSSFWorkbook(classPathResource.getInputStream());
                sheet = wb.getSheetAt(0);
            } catch (Exception e) {
                logger.error("创建工作簿异常", e);
                throw new ServiceException("创建工作簿异常");
            }
            //获取到总记录数
            int total = njtCertificateService.selectTotalCount();
            int saveCount = 0;
            try {
                do {
                    //1.1.分批次查询mysql合格证数据
                    PageHelper.startPage(pageNo++, pageSize);
                    List<NjtCertificateVo> list = njtCertificateService.selectNjtCertificateAllList();
                    if (CollectionUtils.isEmpty(list)) {
                        //意味着没有新的数据，可以直接下载文件了
                        break;
                    }
                    size = list.size();
                    saveCount += size;
                    //计算进度
                    progress = (int) (saveCount * 100.0 / total);
                    logger.info("导出进度：{}%", progress);
                    //1.2.将查询到的mysql数据写入到临时excel文件中
                    for (NjtCertificateVo vo : list) {
                        //获取到当前sheet最后一行
                        int lastRowNum = sheet.getLastRowNum();
                        //创建新行
                        XSSFRow row = sheet.createRow(lastRowNum + 1);
                        //创建单元格并写入数据
                        int cellNum = 0;
                        XSSFCell cell = row.createCell(cellNum++);
                        cell.setCellValue(vo.getUserPerfect().getId());
                        cell = row.createCell(cellNum++);
                        cell.setCellValue(vo.getProductName());
                        cell = row.createCell(cellNum++);
                        cell.setCellValue(vo.getProductWeight().toString());
                        cell = row.createCell(cellNum);
                        cell.setCellValue(vo.getUnit());
                    }
                    //保存到临时文件
                    try(FileOutputStream outputStream = new FileOutputStream(pathname)) {
                        logger.info("写入临时文件条数：{}", size);
                        wb.write(outputStream);
                    } catch (IOException e) {
                        logger.error("写入临时文件异常", e);
                        throw new ServiceException("写入临时文件异常");
                    }
                } while (size == pageSize);
            } finally {
                try {
                    wb.close();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                //释放信号量
                semaphore.release();
//                lock.unlock();
            }
        });
        logger.info("创建临时文件结束-------");
        return AjaxResult.success(filename);
    }

    @PostMapping("/download")
    public void download(@RequestParam("tempFile") String tempFile,HttpServletResponse response) {
        //2.将完整的excel文件发送给客户端
        //设置响应头(excel文件)
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        //设置字符集
        response.setCharacterEncoding("UTF-8");
        String dicPath = RuoYiConfig.getProfile() + "/excel/";
        String pathname = dicPath + tempFile;
        try (FileInputStream fileInputStream = new FileInputStream(pathname)){
            //读取临时文件,并写入到response的响应流中
            byte[] buffer = new byte[1024];
            while (fileInputStream.read(buffer) != -1) {
                response.getOutputStream().write(buffer);
            }
        } catch (Exception e) {
            logger.error("读取临时文件异常", e);
            throw new ServiceException("读取临时文件异常");
        } finally {
            //删除临时文件
//            new File(pathname).delete();
        }

    }


    @PreAuthorize("@ss.hasPermi('certificate:certificate:export')")
    @Log(title = "合格证打印数据", businessType = BusinessType.EXPORT)
    @GetMapping("/progress")
    public AjaxResult progress() {
        return AjaxResult.success(progress);
    }



    /**
     * 获取合格证打印数据详细信息
     */
    @PreAuthorize("@ss.hasPermi('certificate:certificate:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(njtCertificateService.selectNjtCertificateById(id));
    }



    /**
     * 新增合格证打印数据
     */
    @PreAuthorize("@ss.hasPermi('certificate:certificate:add')")
    @Log(title = "合格证打印数据", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody NjtCertificate njtCertificate) {
        return toAjax(njtCertificateService.insertNjtCertificate(njtCertificate));
    }

    /**
     * 修改合格证打印数据
     */
    @PreAuthorize("@ss.hasPermi('certificate:certificate:edit')")
    @Log(title = "合格证打印数据", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody NjtCertificate njtCertificate) {
        return toAjax(njtCertificateService.updateNjtCertificate(njtCertificate));
    }

    /**
     * 删除合格证打印数据
     */
    @PreAuthorize("@ss.hasPermi('certificate:certificate:remove')")
    @Log(title = "合格证打印数据", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(njtCertificateService.deleteNjtCertificateByIds(ids));
    }


    /**
     * 根据合格证编号查询合格证信息
     *
     * @param code
     * @return
     */
    @GetMapping("/code/{code}")
    public AjaxResult queryByCode(@PathVariable("code") String code) {
        return AjaxResult.success(njtCertificateService.getByCode(code));
    }
}
